﻿
using Cms.Core.Data.Infrastructure;
using Cms.Core.Infrastructure.Entity;
using Cms.Core.Infrastructure.Ui;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Cms.Core.Data.UnitOfWork
{
    public interface IRepository<TEntity> : IRepository<TEntity, Guid>
        where TEntity : class, IEFEntityBase
    {

    }
    public interface IRepository<TEntity, TPrimaryKey>
        where TEntity : class, IEFEntityBase<TPrimaryKey>
    {


        #region 查询
         IQueryable<TEntity> Entities { get; }

        IQueryable<TEntity> TrackEntities { get; }
        IQueryable<TEntity> QueryNotDelete { get; }

        IQueryable<TEntity> QueryDelete { get; }

        /// <summary>
        /// 以DTO查询
        /// </summary>
        /// <typeparam name="EntityDto">DTO动态实体</typeparam>
        /// <param name="predicate"></param>
        /// <returns></returns>
        IQueryable<EntityDto> TrackingQueryToDto<EntityDto>(Expression<Func<EntityDto, bool>> predicate) where EntityDto : IEntityDto<TPrimaryKey>;

        /// <summary>
        /// 以DTO查询
        /// </summary>
        /// <returns></returns>
        IQueryable<EntityDto> TrackingQueryToDto<EntityDto>() where EntityDto : IEntityDto<TPrimaryKey>;

        IQueryable<TEntity> TrackingQuery(Expression<Func<TEntity, bool>> predicate);

        /// <summary>
        /// 跟踪查询
        /// </summary>
        /// <returns></returns>
        IQueryable<TEntity> TrackingQuery();

        /// <summary>
        /// 以DTO查询
        /// </summary>
        /// <returns></returns>
        IQueryable<EntityDto> QueryToDto<EntityDto>(Expression<Func<EntityDto, bool>> predicate) where EntityDto : IEntityDto<TPrimaryKey>;



        /// <summary>
        /// 不跟踪查询
        /// </summary>
        /// <returns></returns>
        IQueryable<TEntity> Query(Expression<Func<TEntity, bool>> predicate);

        /// <summary>
        /// 以DTO查询
        /// </summary>
        /// <returns></returns>
        IQueryable<EntityDto> QueryToDto<EntityDto>() where EntityDto : IEntityDto<TPrimaryKey>;

        /// <summary>
        /// 不跟踪查询
        /// </summary>
        /// <returns></returns>
        IQueryable<TEntity> Query();

        /// <summary>
        /// 以主键查询
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns>得到实体</returns>
        TEntity Get(TPrimaryKey id);

        /// <summary>
        /// 异步以主键查询
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns>得到实体</returns>
        Task<TEntity> GetAsync(TPrimaryKey id);


        /// <summary>
        ///以条件查询
        /// </summary>
        /// <param name="predicate">条件</param>
        /// <returns>得到实体</returns>
         TEntity Get(Expression<Func<TEntity, bool>> predicate);

        /// <summary>
        /// 异步以条件查询
        /// </summary>
        /// <param name="predicate">条件</param>
        /// <returns>得到实体</returns>
         Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> predicate);

        /// <summary>
        /// 以主键查询
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns>得到实体</returns>
        EntityDto GetDto<EntityDto>(TPrimaryKey id) where EntityDto : class, IEntityDto<TPrimaryKey>, new();

        /// <summary>
        /// 异步以主键查询
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns>得到实体</returns>
        Task<EntityDto> GetDtoAsync<EntityDto>(TPrimaryKey id) where EntityDto : class, IEntityDto<TPrimaryKey>, new();

        /// <summary>
        /// 异步查询得到DTO
        /// </summary>
        /// <typeparam name="EntityDto"></typeparam>
        /// <param name="predicate"></param>
        /// <returns></returns>
        Task<EntityDto> GetDtoAsync<EntityDto>(Expression<Func<TEntity, bool>> predicate) where EntityDto : class, IEntityDto, new();

        /// <summary>
        /// 用sql查询
        /// </summary>
        /// <param name="sql">要执行sql</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        IQueryable<TEntity> FromSql(string sql, params object[] parameters);
        #endregion

        #region 添加


        /// <summary>
        /// 以异步DTO插入实体
        /// </summary>
        /// <typeparam name="EntityDto">添加DTO类型</typeparam>
        /// <param name="dto">添加DTO</param>
        /// <param name="checkFunc">添加信息合法性检查委托</param>
        /// <param name="insertFunc">由DTO到实体的转换委托</param>
        /// <returns>业务操作结果</returns>
        Task<OperationResult> InsertAsync<EntityDto>(EntityDto dto, Func<EntityDto, Task> checkFunc = null, Func<EntityDto, TEntity, Task<TEntity>> insertFunc = null, Func<TEntity, EntityDto> completeFunc = null) where EntityDto : IEntityDto<TPrimaryKey>;

        /// <summary>
        /// 以异步插入实体
        /// </summary>
        /// <param name="entities">集合</param>
        /// <returns>业务操作结果</returns>

        Task<OperationResult> InsertAsync(params TEntity[] entities);

        /// <summary>
        /// 以异步插入实体
        /// </summary>
        /// <param name="entity">要插入的实体</param>
        /// <returns>业务操作结果</returns>
        Task<OperationResult> InsertAsync(TEntity entity);

        /// <summary>
        /// 插入实体
        /// </summary>
        /// <typeparam name="EntityDto">Dto</typeparam>
        /// <param name="dto">要插入Dto</param>
        /// <returns>业务操作结果</returns>
        OperationResult Insert<EntityDto>(EntityDto dto) where EntityDto : IEntityDto<TPrimaryKey>;
        #endregion

        #region 更新


        /// <summary>
        /// 以异步DTO更新实体
        /// </summary>
        /// <typeparam name="EntityDto">更新DTO类型</typeparam>
        /// <param name="dto">更新DTO</param>
        /// <param name="checkFunc">添加信息合法性检查委托</param>
        /// <param name="updateFunc">由DTO到实体的转换委托</param>
        /// <returns>业务操作结果</returns>
        Task<OperationResult> UpdateAsync<EntityDto>(EntityDto dto, Func<EntityDto, TEntity, Task> checkFunc = null, Func<EntityDto, TEntity, Task<TEntity>> updateFunc = null) where EntityDto : class,IEntityDto<TPrimaryKey>,new();





        /// <summary>
        /// 按需不查询更新
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="properties">需更新的属性</param>
        /// <returns>业务操作结果</returns>

        OperationResult UpdateNotQuery(TEntity entity, params Expression<Func<TEntity, object>>[] properties);



        /// <summary>
        /// 异步按需更新
        /// </summary>
        /// <typeparam name="EntityDto">更新DTO类型</typeparam>
        /// <param name="dto">更新DTO</param>
        /// <param name="properties">更新的字段</param>
        /// <returns></returns>
        Task<OperationResult> UpdateNotQueryAsync<EntityDto>(EntityDto dto,Func<EntityDto, TEntity, Task> checkFunc = null, Func<EntityDto, TEntity, Task<TEntity>> updateFunc = null, params Expression<Func<EntityDto, object>>[] properties);


        #endregion


        #region 删除
        /// <summary>
        /// 以异步软删除数据
        /// </summary>
        /// <typeparam name="key">键</typeparam>
        /// <returns>业务操作结果</returns>
        Task<OperationResult> SoftDeleteAsync(TPrimaryKey id);

        /// <summary>
        /// 以异步批量软删除数据
        /// </summary>
        /// <typeparam name="key">键</typeparam>
        /// <returns></returns>

        Task<int> SoftDeleteBatchAsync(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, TEntity>> updateFactory, CancellationToken cancellationToken = default(CancellationToken));

        /// <summary>
        /// 以异步删除数据
        /// </summary>
        /// <typeparam name="key">键</typeparam>
        /// <param name="checkFunc">删除前置检查委托</param>
        /// <param name="delteFunc">删除委托，用于删除关联信息</param>
        /// <returns>业务操作结果</returns>
        Task<OperationResult> DeleteAsync(TPrimaryKey key, Func<TEntity, Task> checkFunc = null,
            Func<TEntity, Task<TEntity>> delteFunc = null);

        /// <summary>
        /// 异步删除所有符合特定条件的实体
        /// </summary>
        /// <param name="predicate">查询条件谓语表达式</param>
        /// <returns>操作影响的行数</returns>
        Task<int> DeleteBatchAsync(Expression<Func<TEntity, bool>> predicate);


        #endregion


        #region 其他
        /// <summary>
        /// 检查实体
        /// </summary>
        /// <param name="predicate"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        Task<bool> CheckExistsAsync(Expression<Func<TEntity, bool>> predicate, TPrimaryKey id = default(TPrimaryKey));

        /// <summary>
        /// 获得更改跟踪器或Null
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        TEntity GetFromChangeTrackerOrNull(TPrimaryKey id);


        void AttachIfNot(TEntity entity);

        #endregion
    }
}
